/*
 * Copyright 2011 Daniel Krieg
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.code.csf.locators.jaxrpc;

import javax.xml.namespace.QName;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.net.URL;

public class JaxRpcServiceFactoryServiceLocator<ServiceType> extends AbstractJaxRpcServiceLocator<ServiceType> {
    private Class serviceFactoryClass;
    private URL wsdlDocumentUrl;

    public URL getWsdlDocumentUrl() {
        return wsdlDocumentUrl;
    }

    public void setWsdlDocumentUrl(URL wsdlDocumentUrl) {
        this.wsdlDocumentUrl = wsdlDocumentUrl;
    }

    public Class getServiceFactoryClass() {
        return serviceFactoryClass;
    }

    public void setServiceFactoryClass(Class serviceFactoryClass) {
        this.serviceFactoryClass = serviceFactoryClass;
    }

    protected Object createJaxService() throws Throwable {
        Object serviceFactory = createJaxRpcServiceFactory();
        return serviceFactory.getClass()
                .getMethod("createService", URL.class, QName.class)
                .invoke(serviceFactory, getWsdlDocumentUrl(), getQName());
    }

    protected Object createJaxRpcServiceFactory() throws Throwable {
        return getServiceFactoryClass() == null
                ? Class.forName("javax.xml.rpc.ServiceFactory").getMethod("newInstance").invoke(null)
                : instantiateClass(getServiceFactoryClass());
    }

    private static Object instantiateClass(Class clazz) throws Throwable {
        if (clazz.isInterface()) {
            throw new IllegalArgumentException("Specified class [" + clazz.getName() + " is an interface");
        }
        Constructor ctor = clazz.getDeclaredConstructor();
        if ((!Modifier.isPublic(ctor.getModifiers())
                || !Modifier.isPublic(ctor.getDeclaringClass().getModifiers())
                || Modifier.isFinal(ctor.getModifiers()))
                && !ctor.isAccessible()) {
            ctor.setAccessible(true);
        }

        return ctor.newInstance();
    }
}
